home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / ins2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  6.4 KB  |  345 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: ins2.c,v 2.4 84/10/26 12:08:24 guido Exp $";
  3.  
  4. /*
  5.  * B editor -- Insert characters from keyboard.
  6.  */
  7.  
  8. #include "b.h"
  9. #include "bobj.h"
  10. #include "node.h"
  11. #include "supr.h"
  12. #include "queu.h"
  13. #include "gram.h"
  14. #include "tabl.h"
  15.  
  16.  
  17. /*
  18.  * Insert a character.
  19.  */
  20.  
  21. Visible bool
  22. ins_char(ep, c, alt_c)
  23.     register environ *ep;
  24.     int c;
  25.     int alt_c;
  26. {
  27.     auto queue q = Qnil;
  28.     auto queue qf = Qnil;
  29.     auto value copyout();
  30.     auto string str;
  31.     char buf[2];
  32.     int where;
  33.     bool spwhere;
  34.  
  35.     higher(ep);
  36.     shrink(ep);
  37.     if (index("({[`'\"", c) && !ishole(ep)) {
  38.         /* Surround something.  Wonder what will happen! */
  39.         qf = (queue) copyout(ep);
  40.         if (!delbody(ep)) {
  41.             qrelease(qf);
  42.             return No;
  43.         }
  44.     }
  45.     fixit(ep);
  46.     ep->changed = Yes;
  47.     buf[0] = c;
  48.     buf[1] = 0;
  49.     if (!ins_string(ep, buf, &q, alt_c))
  50.         return No;
  51.     if (!emptyqueue(q) || !emptyqueue(qf)) {
  52.         /* Slight variation on app_queue */
  53.         if (!emptyqueue(qf) && emptyqueue(q))
  54.             ritevhole(ep); /* Wizardry.  Why does this work? */
  55.         spwhere = ep->spflag;
  56.         ep->spflag = No;
  57.         where = focoffset(ep);
  58.         markpath(&ep->focus, 1);
  59.         ep->spflag = spwhere;
  60.         if (ep->mode == FHOLE && ep->s2 > 0) {
  61.             /* If we just caused a suggestion, insert the remains
  62.                after the suggested text, not after its first character. */
  63.             str = "";
  64.             if (!soften(ep, &str, 0)) {
  65.                 ep->mode = ATEND;
  66.                 leftvhole(ep);
  67.                 if (symbol(tree(ep->focus)) == Hole) {
  68.                     ep->mode = ATBEGIN;
  69.                     leftvhole(ep);
  70.                 }
  71.             }
  72.         }
  73.         if (!emptyqueue(q)) { /* Re-insert stuff queued by ins_string */
  74.             if (!ins_queue(ep, &q, &q))
  75.                 return No;
  76.             where += spwhere;
  77.             spwhere = No;
  78.         }
  79.         if (!emptyqueue(qf)) { /* Re-insert deleted old focus */
  80.             firstmarked(&ep->focus, 1) || Abort();
  81.             fixfocus(ep, where);
  82.             if (!ins_queue(ep, &qf, &qf))
  83.                 return No;
  84.         }
  85.         firstmarked(&ep->focus, 1) || Abort();
  86.         unmkpath(&ep->focus, 1);
  87.         ep->spflag = No;
  88.         fixfocus(ep, where + spwhere);
  89.     }
  90.     return Yes;
  91. }
  92.  
  93.  
  94. /*
  95.  * Insert a newline.
  96.  */
  97.  
  98. Visible bool
  99. ins_newline(ep)
  100.     register environ *ep;
  101. {
  102.     register node n;
  103.     register int sym;
  104.     auto bool mayindent;
  105.  
  106.     ep->changed = Yes;
  107.     if (!fiddle(ep, &mayindent))
  108.         return No;
  109.     for (;;) {
  110.         switch (ep->mode) {
  111.  
  112.         case VHOLE:
  113.             ep->mode = ATEND;
  114.             continue;
  115.  
  116.         case FHOLE:
  117.             ep->s2 = lenitem(ep);
  118.             if (!fix_move(ep))
  119.                 return No;
  120.             continue;
  121.  
  122.         case ATEND:
  123.             if (!joinstring(&ep->focus, "\n", No, 0, mayindent)) {
  124.                 if (!move_on(ep))
  125.                     return No;
  126.                 continue;
  127.             }
  128.             s_downi(ep, 2);
  129.             s_downi(ep, 1);
  130.             ep->mode = WHOLE;
  131.             Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
  132.             return Yes;
  133.  
  134.         case ATBEGIN:
  135.             n = tree(ep->focus);
  136.             if (Type(n) == Tex) {
  137.                 ep->mode = ATEND;
  138.                 continue;
  139.             }
  140.             sym = symbol(n);
  141.             if (sym == Hole || sym == Optional) {
  142.                 ep->mode = WHOLE;
  143.                 continue;
  144.             }
  145.             n = nodecopy(n);
  146.             if (!fitstring(&ep->focus, "\n", 0)) {
  147.                 if (!down(&ep->focus))
  148.                     ep->mode = ATEND;
  149.                 noderelease(n);
  150.                 continue;
  151.             }
  152.             s_downrite(ep);
  153.             if (fitnode(&ep->focus, n)) {
  154.                 noderelease(n);
  155.                 s_up(ep);
  156.                 s_down(ep);
  157.                 ep->mode = WHOLE;
  158.                 return Yes;
  159.             }
  160.             s_up(ep);
  161.             s_down(ep);
  162.             if (!fitnode(&ep->focus, n)) {
  163.                 noderelease(n);
  164. #ifndef NDEBUG
  165.                 debug("[Sorry, I don't see how to insert a newline here]");
  166. #endif NDEBUG
  167.                 return No;
  168.             }
  169.             noderelease(n);
  170.             ep->mode = ATBEGIN;
  171.             return Yes;
  172.  
  173.         case WHOLE:
  174.             Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
  175.             if (!fitstring(&ep->focus, "\n", 0)) {
  176.                 ep->mode = ATEND;
  177.                 continue;
  178.             }
  179.             s_downi(ep, 1);
  180.             Assert((sym = symbol(tree(ep->focus))) == Hole || sym == Optional);
  181.             ep->mode = WHOLE;
  182.             return Yes;
  183.  
  184.         default:
  185.             Abort();
  186.  
  187.         }
  188.     }
  189. }
  190.  
  191.  
  192. /*
  193.  * Refinement for ins_newline() to do the initial processing.
  194.  */
  195.  
  196. Hidden bool
  197. fiddle(ep, pmayindent)
  198.     register environ *ep;
  199.     bool *pmayindent;
  200. {
  201.     register int level;
  202.     auto string str = "";
  203.  
  204.     higher(ep);
  205.     while (rnarrow(ep))
  206.         ;
  207.     fixit(ep);
  208.     soften(ep, &str, 0);
  209.     higher(ep);
  210.     *pmayindent = Yes;
  211.     if (atdedent(ep)) {
  212.         *pmayindent = No;
  213.         s_up(ep);
  214.         level = Level(ep->focus);
  215.         delfocus(&ep->focus);
  216.         if (symbol(tree(ep->focus)) == Hole) {
  217.             if (hackhack(ep))
  218.                 return Yes;
  219.         }
  220.         while (Level(ep->focus) >= level) {
  221.             if (!nexthole(ep)) {
  222.                 ep->mode = ATEND;
  223.                 break;
  224.             }
  225.         }
  226.         if (ep->mode == ATEND) {
  227.             leftvhole(ep);
  228.             ep->mode = ATEND;
  229.             while (Level(ep->focus) >= level) {
  230.                 if (!up(&ep->focus))
  231.                     return No;
  232.             }
  233.         }
  234.         return Yes;
  235.     }
  236.     return Yes;
  237. }
  238.  
  239.  
  240. /*
  241.  * "Hier komen de houthakkers."
  242.  *
  243.  * Incredibly ugly hack to delete a join whose second child begins with \n,
  244.  * such as a suite after an IF, FOR or WHILE or  unit heading.
  245.  * Inspects the parent node.
  246.  * If this has rp[0] ands rp[1] both empty, replace it by its first child.
  247.  * (caller assures this makes sense).
  248.  * Return Yes if this happened AND rp[1] contained a \t.
  249.  */
  250.  
  251. Hidden Procedure
  252. hackhack(ep)
  253.     environ *ep;
  254. {
  255.     node n;
  256.     int ich = ichild(ep->focus);
  257.     string *rp;
  258.  
  259.     if (!up(&ep->focus))
  260.         return No;
  261.     higher(ep);
  262.     rp = noderepr(tree(ep->focus));
  263.     if (!Fw_zero(rp[0]) || !Fw_zero(rp[1])) {
  264.         s_downi(ep, ich);
  265.         return No;
  266.     }
  267.     n = nodecopy(firstchild(tree(ep->focus)));
  268.     delfocus(&ep->focus);
  269.     replace(&ep->focus, n);
  270.     ep->mode = ATEND;
  271.     return rp[1] && rp[1][0] == '\t';
  272. }
  273.     
  274.  
  275. /*
  276.  * Refinement for fiddle() to find out whether we are at a possible
  277.  * decrease-indentation position.
  278.  */
  279.  
  280. Hidden bool
  281. atdedent(ep)
  282.     register environ *ep;
  283. {
  284.     register path pa;
  285.     register node npa;
  286.     register int i;
  287.     register int sym = symbol(tree(ep->focus));
  288.  
  289.     if (sym != Hole && sym != Optional)
  290.         return No;
  291.     if (ichild(ep->focus) != 1)
  292.         return No;
  293.     switch (ep->mode) {
  294.     case FHOLE:
  295.         if (ep->s1 != 1 || ep->s2 != 0)
  296.             return No;
  297.         break;
  298.     case ATBEGIN:
  299.     case WHOLE:
  300.     case SUBSET:
  301.         break;
  302.     default:
  303.         return No;
  304.     }
  305.     pa = parent(ep->focus);
  306.     if (!pa)
  307.         return No;
  308.     npa = tree(pa);
  309.     if (fwidth(noderepr(npa)[0]) >= 0)
  310.         return No;
  311.     for (i = nchildren(npa); i > 1; --i) {
  312.         sym = symbol(child(npa, i));
  313.         if (sym != Hole && sym != Optional)
  314.             return No;
  315.     }
  316.     return Yes; /* Sigh! */
  317. }
  318.  
  319. /*
  320.  * Refinement for ins_node() and fiddle() to find the next hole,
  321.  * skipping blank space only.
  322.  */
  323.  
  324. Hidden bool
  325. nexthole(ep)
  326.     register environ *ep;
  327. {
  328.     register node n;
  329.     register int ich;
  330.     register string repr;
  331.  
  332.     do {
  333.         ich = ichild(ep->focus);
  334.         if (!up(&ep->focus))
  335.             return No;
  336.         higher(ep);
  337.         n = tree(ep->focus);
  338.         repr = noderepr(n)[ich];
  339.         if (!Fw_zero(repr) && !allspaces(repr))
  340.             return No;
  341.     } while (ich >= nchildren(n));
  342.     s_downi(ep, ich+1);
  343.     return Yes;
  344. }
  345.